#ifndef _NTH_LIB_H
#include <nth-lib.h>
#endif

#ifndef _STDLIB_H
#include <stdlib.h>
#endif

#ifndef _STRING_H
#include <string.h>
#endif

int Clean_Nth_Plugin(struct Nth_Plugin * nth_plugin){

	if (!nth_plugin){
		return NTH_ERROR_NULL_POINTER;
	}

	if (nth_plugin->plugin_name){
		free(nth_plugin->plugin_name);
		nth_plugin->plugin_name = 0;
	}

	if (nth_plugin->plugin_description){
		free(nth_plugin->plugin_description);
		nth_plugin->plugin_description = 0;
	}

	return 0;
}

int Initialize_Nth_Plugin(struct Nth_Plugin * nth_plugin){

	char plugin_name[] = "multiply";
	char plugin_desc[] = "Multiply two or more expressions";

	if (!nth_plugin){
		return NTH_ERROR_NULL_POINTER;
	}

	nth_plugin->plugin_name = malloc(sizeof(plugin_name));

	if (!nth_plugin->plugin_name){
		return NTH_ERROR_NO_MEMORY;
	}

	memcpy(
		nth_plugin->plugin_name,
		plugin_name,
		sizeof(plugin_name)
	);

	nth_plugin->plugin_description = malloc(sizeof(plugin_desc));

	if (!nth_plugin){
		free(nth_plugin->plugin_description);
		nth_plugin->plugin_description = 0;
		return NTH_ERROR_NO_MEMORY;
	}

	memcpy(
		nth_plugin->plugin_description,
		plugin_desc,
		sizeof(plugin_desc)
	);

	nth_plugin->plugin_callback = Nth_Plugin_Callback;

	return 0;
}

int Nth_Plugin_Callback(
	struct Nth_Program * nth_program,
	struct Nth_Number * plugin_number
){
	int error = 0;

	struct Nth_Multiplication nth_multiplication;

	if (!nth_program || !plugin_number){
		return 1;
	}

	memset(&nth_multiplication, 0, sizeof(nth_multiplication));

	error = Evaluate_Nth_Expression(
		nth_program,
		&nth_multiplication.operand_one
	);

	if (error){

		Clean_Nth_Number(&nth_multiplication.operand_one);

		Push_Nth_Failure(
			nth_program,
			"Nth_Plugin_Callback",
			"Failed to get first operand"
		);

		return 1;
	}

	error = Evaluate_Nth_Expression(
		nth_program,
		&nth_multiplication.operand_two
	);

	if (error){

		Clean_Nth_Number(&nth_multiplication.operand_one);
		Clean_Nth_Number(&nth_multiplication.operand_two);

		Push_Nth_Failure(
			nth_program,
			"Nth_Plugin_Callback",
			"Failed to get second operand"
		);

		return 1;
	}

	error = Set_Nth_Number_Length(
		&nth_multiplication.product,
		  nth_multiplication.operand_one.number_length
		+ nth_multiplication.operand_two.number_length
	);

	if (error){

		Clean_Nth_Number(&nth_multiplication.operand_one);
		Clean_Nth_Number(&nth_multiplication.operand_two);
		Clean_Nth_Number(&nth_multiplication.product);

		Push_Nth_Failure(
			nth_program,
			"Nth_Plugin_Callback",
			"Failed to set product length"
		);

		return 1;
	}

	error = Multiply_Nth_Numbers(&nth_multiplication);

	if (error){

		Clean_Nth_Number(&nth_multiplication.operand_one);
		Clean_Nth_Number(&nth_multiplication.operand_two);
		Clean_Nth_Number(&nth_multiplication.product);

		Push_Nth_Failure(
			nth_program,
			"Nth_Plugin_Callback",
			"Failed to multiply operands"
		);

		return 1;
	}

	Clean_Nth_Number(&nth_multiplication.operand_one);
	Clean_Nth_Number(&nth_multiplication.operand_two);

	plugin_number->number_buffer = nth_multiplication.product.number_buffer;
	plugin_number->number_length = nth_multiplication.product.number_length;

	return 0;
}

